﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Xml;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Epi;
using Epi.ImportExport;
using Epi.ImportExport.Filters;
using Epi.ImportExport.ProjectPackagers;
using Menafrinet.ViewModel;
using Menafrinet.View.Controls;

namespace Menafrinet.View.Controls
{
    /// <summary>
    /// Interaction logic for MergePanel.xaml
    /// </summary>
    public partial class MergePanel : UserControl
    {
        public delegate void ImportCompletedHandler(List<ImportInfo> info);

        private DataHelper DataHelper
        {
            get
            {
                return (this.DataContext as DataHelper);
            }
        }

        public bool IsMerging { get; private set; }

        public MergePanel()
        {
            InitializeComponent();
        }

        private void btnOpenFolder_Click(object sender, RoutedEventArgs e)
        {
            FileInfo fi = new FileInfo(DataHelper.Project.FilePath);
            DirectoryInfo di = new DirectoryInfo(System.IO.Path.Combine(fi.Directory.FullName, Properties.Settings.Default.DataImportFolder));
            System.Diagnostics.Process.Start("explorer.exe", di.FullName);
        }

        private void btnImport_Click(object sender, RoutedEventArgs e)
        {
            if (!(Application.Current as App).CanMerge)
            {
                MessageBox.Show("Cannot merge data while generating a transmission file.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            txtImportStatus.Text = String.Empty;

            ImportSettings settings = new ImportSettings();

            settings.DestinationLanguage = Properties.Settings.Default.Language.ToLower();
            settings.Project = DataHelper.Project;
            settings.ProjectPath = DataHelper.ProjectPath;
            settings.CaseForm = DataHelper.CaseForm;
            settings.Database = DataHelper.Database;

            FileInfo fi = new FileInfo(DataHelper.Project.FilePath);
            settings.InputDirectory = new DirectoryInfo(System.IO.Path.Combine(fi.Directory.FullName, Properties.Settings.Default.DataImportFolder));

            settings.ArchiveDirectory = new DirectoryInfo(System.IO.Path.Combine(settings.InputDirectory.FullName, Properties.Settings.Default.DataImportArchiveFolder));

            if(settings.InputDirectory.GetFiles("*.edp7").Length == 0)
            {
                MessageBox.Show("There are no data packages in the import folder.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            DateTime dt = DateTime.UtcNow;
            string dateDisplayValue = String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:s}", dt);
            dateDisplayValue = dateDisplayValue.Replace(':', '-'); // The : must be replaced otherwise the encryption fails

            btnImport.IsEnabled = false;
            importProgressBar.IsIndeterminate = true;
            (Application.Current as App).CanMerge = false;
            (Application.Current as App).CanTransmit = false;

            this.DataHelper.TaskbarProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;

            BackgroundWorker exportWorker = new BackgroundWorker();
            exportWorker.DoWork += new DoWorkEventHandler(importWorker_DoWork);
            exportWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(importWorker_RunWorkerCompleted);
            exportWorker.RunWorkerAsync(settings);
        }

        void importWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            List<ImportInfo> infos = (List<ImportInfo>)e.Result;
            this.Dispatcher.BeginInvoke(new ImportCompletedHandler(UpdateImportInfo), infos);
            (Application.Current as App).CanMerge = true;
            (Application.Current as App).CanTransmit = true;

            this.DataHelper.TaskbarProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
        }

        void importWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            ImportSettings settings = (ImportSettings)e.Argument;
            List<ImportInfo> infos = MergeDataPackages(settings);
            e.Result = infos;
        }

        private List<ImportInfo> MergeDataPackages(ImportSettings settings)
        {
            List<ImportInfo> importInfos = new List<ImportInfo>();
            List<FileInfo> packagePaths = new List<FileInfo>();
            List<string> unimportedPackagePaths = new List<string>();

            foreach (System.IO.FileInfo f in settings.InputDirectory.GetFiles("*.edp7"))
            {
                string fileName = f.FullName;

                if (!fileName.EndsWith(".edp7") ||
                    !f.Name.StartsWith("MENAFRINET_") 
                    )
                {
                    unimportedPackagePaths.Add(fileName);
                    CallbackSetStatusMessage(String.Format("Package {0} was not included in the merge due to validation errors.", f.Name));
                }
                else
                {
                    packagePaths.Add(f);
                }
            }

            foreach (FileInfo packagePath in packagePaths)
            {
                try
                {
                    string fileName = packagePath.FullName;
                    string str = Configuration.DecryptFileToString(fileName, String.Empty);

                    str = str.Remove(0, 24);

                    string plainText = ImportExportHelper.UnZip(str);

                    XmlDocument xmlDataPackage = new XmlDocument();
                    xmlDataPackage.LoadXml(plainText);

                    #region Xml validation
                    // First check - never import a package that didn't originate at the proper 'level'. For example,
                    // a district shouldn't import from the MoH. System levels are included as attributes in the data
                    // package so we can check for that before merging the data.
                    int sourceSystemLevel = int.Parse(xmlDataPackage.ChildNodes[0].Attributes["SystemLevel"].Value.ToString());
                    int currentSystemLevel = Properties.Settings.Default.SystemLevel;

                    if (!(
                        (currentSystemLevel == 1 && sourceSystemLevel == 0) || // NRL receives data from district
                        (currentSystemLevel == 0 && sourceSystemLevel == 1) || // District receives data from NRL
                        (currentSystemLevel == 2 && sourceSystemLevel == 1) || // Region receives data from NRL
                        (currentSystemLevel == 3 && sourceSystemLevel == 1) || // MoH receives data from NRL
                        (currentSystemLevel == 4 && sourceSystemLevel == 3) || // Menafrinet receives data from MoH
                        (sourceSystemLevel == 3)                               // Any system receives MoH data
                        ))
                    {
                        CallbackSetStatusMessage(String.Format("Package {0} was not included in the merge. It's system level is {1}, but the current system level is {2}.", packagePath.Name, sourceSystemLevel.ToString(), currentSystemLevel.ToString()));
                        continue;
                    }
                    #endregion // Xml validation

                    string language = Properties.Settings.Default.Language.ToLower();
                    if (!language.Equals("en-us"))
                    {
                        CallbackSetStatusMessage(String.Format("Translating field names in data package from {0}...", settings.DestinationLanguage));
                        xmlDataPackage = Core.Common.TranslateDataPackageFieldsFromInvariant(xmlDataPackage, settings.DestinationLanguage);
                        CallbackSetStatusMessage("Translation of field names complete.");
                    }

                    Epi.Fields.Field epidField = settings.CaseForm.Fields["EpidShow"];

                    XmlMultiKeyDataUnpackager xmlMultiKeyUP = new XmlMultiKeyDataUnpackager(settings.CaseForm, xmlDataPackage);
                    //xmlUP.StatusChanged += new UpdateStatusEventHandler(CallbackSetStatusMessage);
                    //xmlUP.UpdateProgress += new SetProgressBarDelegate(CallbackSetProgressBar);
                    //xmlUP.ResetProgress += new SimpleEventHandler(CallbackResetProgressBar);
                    xmlMultiKeyUP.MessageGenerated += new UpdateStatusEventHandler(CallbackSetStatusMessage);
                    //xmlUP.ImportFinished += new EventHandler(xmlUP_ImportFinished);
                    xmlMultiKeyUP.Append = true;
                    //xmlMultiKeyUP.KeyFields.Add(epidField);
                    xmlMultiKeyUP.Update = true;
                    xmlMultiKeyUP.Unpackage();
                    importInfos.Add(xmlMultiKeyUP.ImportInfo);

                    //XmlDataUnpackager xmlUP = new Epi.ImportExport.ProjectPackagers.XmlDataUnpackager(settings.CaseForm, xmlDataPackage);
                    ////xmlUP.StatusChanged += new UpdateStatusEventHandler(CallbackSetStatusMessage);
                    ////xmlUP.UpdateProgress += new SetProgressBarDelegate(CallbackSetProgressBar);
                    ////xmlUP.ResetProgress += new SimpleEventHandler(CallbackResetProgressBar);
                    //xmlUP.MessageGenerated += new UpdateStatusEventHandler(CallbackSetStatusMessage);
                    ////xmlUP.ImportFinished += new EventHandler(xmlUP_ImportFinished);
                    //xmlUP.Append = true;
                    //xmlUP.Update = true;
                    //xmlUP.Unpackage();
                    //importInfos.Add(xmlUP.ImportInfo);

                    //FileInfo fi = new FileInfo(packagePath);

                    string archiveFile = System.IO.Path.Combine(settings.ArchiveDirectory.FullName, packagePath.Name);

                    System.IO.File.Move(fileName, archiveFile);

                    string siteCode = xmlDataPackage.ChildNodes[0].Attributes["SiteCode"].Value;
                    CallbackUpdateSiteStatus(siteCode);
                }
                catch (Exception ex)
                {
                    CallbackSetStatusMessage(ex.Message);
                    //info.AddError(ex.Message, String.Empty);
                    //e.Result = ex;
                }
            }

            return importInfos;
            //AddNotificationStatusMessage(string.Format(ImportExportSharedStrings.START_BATCH_IMPORT, packagePaths.Count.ToString(), txtPackageFile.Text));
        }

        private void CallbackUpdateSiteStatus(string code)
        {
            this.Dispatcher.BeginInvoke(new UpdateStatusEventHandler(UpdateSiteStatus), code);
        }

        private void UpdateSiteStatus(string code)
        {
            DataHelper.UpdateSite(code);
        }

        private void SetProgressBar(double value)
        {
            importProgressBar.Value = value;
            this.DataHelper.TaskbarProgressValue = value / 100;
        }

        private void SetStatusMessage(string message)
        {
            txtImportStatus.Text = txtImportStatus.Text + DateTime.Now.ToString() + " | " + message + "\n";
        }

        private void CallbackSetProgressBar(double value)
        {
            this.Dispatcher.BeginInvoke(new SetProgressBarDelegate(SetProgressBar), value);
        }

        private void CallbackSetStatusMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new UpdateStatusEventHandler(SetStatusMessage), message);
        }

        private void UpdateImportInfo(List<ImportInfo> infos)
        {
            Properties.Settings.Default.UserLastMerged = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
            Properties.Settings.Default.DateLastMerged = DateTime.Now;
            Properties.Settings.Default.PackagesLastMerged = infos.Count;

            int total = 0;

            foreach (ImportInfo info in infos)
            {
                total = total + info.TotalRecordsAppended;
            }

            Properties.Settings.Default.RecordsLastMerged = total;
            Properties.Settings.Default.Save();

            importProgressBar.Value = 0;
            importProgressBar.IsIndeterminate = false;
            btnImport.IsEnabled = true;
            
            SetStatusMessage("Merge complete.");

            DataHelper.RepopulateCollections();
        }

        internal void ResetHeight()
        {
            dgSites.Visibility = System.Windows.Visibility.Collapsed;

            grdHome.UpdateLayout();

            double maxHeight = grdHome.ActualHeight;
            maxHeight = maxHeight - 100;

            if (maxHeight <= 0) maxHeight = 0;

            dgSites.MaxHeight = maxHeight;
            dgSites.Height = maxHeight;
            dgSites.Visibility = System.Windows.Visibility.Visible;

            txtImportStatus.Height = Math.Min(360, Math.Max(40, grdHome.ActualHeight - 310));
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ResetHeight();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            // only show the site merge status for the regional lab
            if (Properties.Settings.Default.SystemLevel != 1)
            {
                panelSiteMergeStatus.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                panelSiteMergeStatus.Visibility = System.Windows.Visibility.Visible;
            }
        }
    }
}
